<?php
/* -------------------------------------------------------------------------------------
* 	ID:						$Id: class.fuzzy_search.php 135 2013-09-22 07:30:55Z phone.mueller@googlemail.com $
* 	Letzter Stand:			$Revision: 135 $
* 	zuletzt geändert von:	$Author: peter $
* 	Datum:					$Date: 2013-09-22 07:30:55 +0000 (Sun, 22 Sep 2013) $
*
* 	SEO:mercari by Siekiera Media
* 	http://www.seo-mercari.de
*
* 	Copyright (c) since 2011 SEO:mercari
* --------------------------------------------------------------------------------------
* 	based on:
* 	(c) 2000-2001 The Exchange Project  (earlier name of osCommerce)
* 	(c) 2002-2003 osCommerce - www.oscommerce.com
* 	(c) 2003     nextcommerce - www.nextcommerce.org
* 	(c) 2005     xt:Commerce - www.xt-commerce.com
*
* 	Released under the GNU General Public License
* ----------------------------------------------------------------------------------- */
 
class FuzzySearch {
	var $keywords;
	var $resultKeywords = array();
	var $resultProducts = array();
	var $parse_time;
	var $db;
	
	function __construct(){
		global $db;
		$this->db = $db;
	}
	
	function getSpecialChars($str){
		$string = strip_tags($str);
		$trans = get_html_translation_table(HTML_ENTITIES);
		$trans = array_flip($trans);
		$string = strtr($string, $trans);
		
		return $string;
	}
	
	function getSuggest($keywords) {
		global $product, $list_data;
		
		define('PARSE_START_TIME', microtime());
	
		$weight_sum = (SEARCH_WEIGHT_LEVENSHTEIN + SEARCH_WEIGHT_SIMILAR_TEXT + SEARCH_WEIGHT_METAPHONE);
	
		if ($weight_sum > 100){
			define('SEARCH_WEIGHT_LEVENSHTEIN', (SEARCH_WEIGHT_LEVENSHTEIN/$weight_sum)*100);
			define('SEARCH_WEIGHT_SIMILAR_TEXT', (SEARCH_WEIGHT_SIMILAR_TEXT/$weight_sum)*100);
			define('SEARCH_WEIGHT_METAPHONE', (SEARCH_WEIGHT_METAPHONE/$weight_sum)*100);
		}
	
		if (SEARCH_WEIGHT_METAPHONE > 0)
			$keyword_metaphone = metaphone($keywords);
	
		$keyword_lev_sim = $keywords;
		$colors = explode(';',SEARCH_PROXIMITY_COLORS);
	
		//fsk18 lock
		if ($_SESSION['customers_status']['customers_fsk18_display'] == '0')
			$fsk_lock = " AND p.products_fsk18 != '1' ";
		else
			unset($fsk_lock);
	
		//group check
		if (GROUP_CHECK == 'true')
			$group_check = " AND p.group_permission_".$_SESSION['customers_status']['customers_status_id']."=1 ";
		else
			unset($group_check);
		
		// search in keywords?
		if (SEARCH_PRODUCT_KEYWORDS == 'true')
			$search_keywords =', pd.products_keywords ';
		else
			unset($search_keywords);
		
		// search in description?
		if (SEARCH_PRODUCT_DESCRIPTION == 'true')
			$search_description =', pd.products_short_description, pd.products_description ';
		else
			unset($search_description);
		
		include(DIR_WS_MODULES.'product_filter.php');
				
		// alle Produktnamen holen
		$product_array = $this->db->db_query("	SELECT 
													pd.products_name".$search_keywords.$search_description."
												FROM 
													".TABLE_PRODUCTS." AS p 
												LEFT JOIN ".TABLE_PRODUCTS_DESCRIPTION." AS pd 
													ON (p.products_id = pd.products_id)
												LEFT JOIN ".TABLE_PRODUCTS_TO_CATEGORIES." AS pc 
													ON (p.products_id = pc.products_id) 
												LEFT JOIN ".TABLE_CATEGORIES." AS c 
													ON (pc.categories_id = c.categories_id)
												WHERE 
													p.products_status = '1'
												AND 
													c.categories_status = 1
												AND 
													pd.language_id = '".(int)$_SESSION['languages_id']."'".$filter_products.$fsk_lock.$group_check);
		
		
		$max_count = 0;
		$results['name'] = array();
		$results['proximity_color'] = array();
		
		// jeden Produktnamen durchlaufen
		while(!$product_array->EOF) {
			
			$word_string = $product_array->fields['products_name'];
			
			if (SEARCH_PRODUCT_KEYWORDS == 'true')
				$word_string .= ' '.$product_array->fields['products_keywords'];
			
			if (SEARCH_PRODUCT_DESCRIPTION == 'true')
				$word_string .= ' '.$this->getSpecialChars($product_array->fields['products_short_description']).' '.$this->getSpecialChars($product_array->fields['products_description']);
			
			// Strings zerlegen 
			if ((SEARCH_SPLIT_PRODUCT_NAMES == 'true') || (SEARCH_PRODUCT_KEYWORDS == 'true') || (SEARCH_PRODUCT_DESCRIPTION == 'true'))
				$split_content = explode(SEARCH_SPLIT_PRODUCT_CHARS, $word_string);
			else
				$split_content[0] = $word_string;        
			     
			$count = 0;
			
			foreach ($split_content AS $split_names) {
				$split_names = trim($split_names);
				if (strlen($split_names) > SEARCH_SPLIT_MINIMUM_LENGTH) {
					if (SEARCH_WEIGHT_LEVENSHTEIN > 0)
						$prl = 100 -(10*levenshtein($keyword_lev_sim, strtolower($split_names)));
			
					if (SEARCH_WEIGHT_SIMILAR_TEXT > 0)
						similar_text($keyword_lev_sim, strtolower($split_names),$prs);
			
					if (SEARCH_WEIGHT_METAPHONE > 0)
						similar_text($keyword_metaphone, metaphone($split_names),$prm);
            
					$pr = ($prl*SEARCH_WEIGHT_LEVENSHTEIN/100)+($prs*SEARCH_WEIGHT_SIMILAR_TEXT/100)+($prm*SEARCH_WEIGHT_METAPHONE/100);

					if (($pr > SEARCH_PROXIMITY_TRIGGER) && (!in_array($split_names, $results['name']))) {
						$proximity = sprintf('%01.0f', $pr);
						$results['name'][$max_count] = $split_names;
						$results['proximity'][$max_count] = $proximity;
					
						if (SEARCH_ENABLE_PROXIMITY_COLOR == 'true'){
							if ($results['proximity'][$max_count] < 60) $proximity_color = $colors[4];
							if ($results['proximity'][$max_count] >= 60) $proximity_color = $colors[3];
							if ($results['proximity'][$max_count] >= 70) $proximity_color = $colors[2];
							if ($results['proximity'][$max_count] >= 80) $proximity_color = $colors[1];
							if ($results['proximity'][$max_count] >= 90) $proximity_color = $colors[0];   
							$results['proximity_color'][$max_count] = $proximity_color;
						} else
							$results['proximity_color'] = array();
						
						$max_count++;
					}
				}
			}
			$product_array->MoveNext();
		}
		
		// Wenn Ergebnisse vorhanden, $results nach Nähe sortieren und ausgeben
		if ($max_count > 0){
			if (SEARCH_ENABLE_PROXIMITY_COLOR == 'true')
				array_multisort ($results['proximity'], SORT_NUMERIC,SORT_DESC, $results['name'], SORT_ASC, SORT_STRING, $results['proximity_color'], SORT_ASC, SORT_STRING );
			else
				array_multisort ($results['proximity'], SORT_NUMERIC,SORT_DESC, $results['name'], SORT_ASC, SORT_STRING);
   
			$counter = 0;
		
			while($results['name'][$counter] && $counter < SEARCH_MAX_KEXWORD_SUGGESTS) {
		
				if (SEARCH_COUNT_PRODUCTS == 'true'){

					if (SEARCH_PRODUCT_KEYWORDS == 'true')
						$count_keywords =" OR pd.products_keywords LIKE ('%".addslashes($results['name'][$counter])."%')";
					else
						unset($count_keywords);
		
					if (SEARCH_PRODUCT_DESCRIPTION == 'true'){
						$count_description =" OR pd.products_short_description LIKE ('%".addslashes(htmlentities($results['name'][$counter]))."%')";
						$count_description .=" OR pd.products_description LIKE ('%".addslashes(htmlentities($results['name'][$counter]))."%')";
					} else
						unset($count_description);
					
					$products_counter = $this->db->db_query("	SELECT 
																	COUNT(*) AS products_count
																FROM 
																	".TABLE_PRODUCTS." AS p 
																LEFT JOIN 
																	".TABLE_PRODUCTS_DESCRIPTION." AS pd 
																ON 
																	(p.products_id = pd.products_id)
																WHERE 
																	p.products_status = '1'
																AND 
																	pd.language_id = '".(int) $_SESSION['languages_id']."'".$fsk_lock.$group_check." 
																AND 
																	( pd.products_name 
																LIKE 
																	('%".addslashes($results['name'][$counter])."%')".$count_keywords.$count_description.")");
					
					$results['products_count'][$counter] = $products_counter->fields['products_count'];
				}
		
				if(MODULE_SEO_URL_INDEX_STATUS == 'True')
					$link = href_link('keywords/'.str_replace(' ','+',$results['name'][$counter]).'/');
				else
					$link = href_link(FILENAME_ADVANCED_SEARCH_RESULT, 'keywords='.urlencode($results['name'][$counter]));
		
				// ins Array        
				$this->resultKeywords[$counter] = array('SUGGEST_KEYWORD' => $results['name'][$counter],
														'SUGGEST_PROXIMITY' => $results['proximity'][$counter].'%',
														'SUGGEST_COUNT' => $results['products_count'][$counter],
														'SUGGEST_COLOR' => $results['proximity_color'][$counter],
														'SUGGEST_LINK' => $link);
				$counter++;
			}
		
			if (SEARCH_ENABLE_PRODUCTS_SUGGEST == 'true'){
				$count = 0;
				$row = 0;
			
				while ($row < SEARCH_MAX_PRODUCTS_SUGGEST) {
					if (SEARCH_PRODUCT_KEYWORDS == 'true')
						$count_keywords = " OR pd.products_keywords LIKE ('%".addslashes($results['name'][$row])."%')";
					else
						unset($count_keywords);
					
					if (SEARCH_PRODUCT_DESCRIPTION == 'true'){
						$count_description = " OR pd.products_short_description LIKE ('%".addslashes(htmlentities($results['name'][$row]))."%')";
						$count_description .= " OR pd.products_description LIKE ('%".addslashes(htmlentities($results['name'][$row]))."%')";
					} else
						unset($count_description);
					
					
					$products_suggest = $this->db->db_query("SELECT DISTINCT 
																pd.products_name,
																p.products_image,
																p.products_id, 
																p.products_price, 
																p.products_tax_class_id, 
																pd.products_id, 
																cd.categories_id, 
																cd.categories_name, 
																ptc.categories_id
															FROM 
																((".TABLE_PRODUCTS." AS p 
																LEFT JOIN ".TABLE_PRODUCTS_DESCRIPTION." AS pd 
																	ON (p.products_id = pd.products_id))
																INNER JOIN ".TABLE_PRODUCTS_TO_CATEGORIES." AS ptc 
																	ON (p.products_id = ptc.products_id))
															INNER JOIN 
																".TABLE_CATEGORIES_DESCRIPTION." AS cd ON (ptc.categories_id = cd.categories_id)
															WHERE 
																p.products_status = '1'
															AND 
																pd.language_id = '".(int) $_SESSION['languages_id']."'".$fsk_lock.$group_check."
															AND 
																( pd.products_name LIKE ('%".addslashes($results['name'][$row])."%')".$count_keywords.$count_description.")
															LIMIT 
																".(SEARCH_MAX_PRODUCTS_SUGGEST-$row));

					while (!$products_suggest->EOF){
						if (($count <= SEARCH_MAX_PRODUCTS_SUGGEST) && ($results['name'][$row])) { $ii++;
							$this->results[$count] = array('CATEGORIES_NAME' => $products_suggest->fields['categories_name'],
	                                                        'CATEGORIES_LINK' => href_link(FILENAME_DEFAULT, 'cPath='.$products_suggest->fields['categories_id']),
	                                                        'PRODUCTS_PROXIMITY' => $results['proximity'][$row].'%',
	                                                        'PRODUCTS_PROXIMITY_COLOR' => $results['proximity_color'][$row]);
					
							$this->resultProducts[$count] = $product->buildDataArray($products_suggest->fields, 'thumbnail', $list_data, $ii);
							$this->new_fuzzy[$count] = array_merge($this->resultProducts[$count], $this->results[$count]);
							$count++;
						}
						$products_suggest->MoveNext();
					}
					$row++;
				}
			}
		} 
		
		if (SEARCH_SHOW_PARSETIME == 'true'){
			$time_start = explode(' ', PARSE_START_TIME);
			$time_end = explode(' ', microtime());
			$this->parse_time = number_format(($time_end[1] + $time_end[0] - ($time_start[1] + $time_start[0])), 3);  
		}
		return $module_content;
	}
}
?>